package inabit.inabitcompiler.lexical;

import inabit.compiler.lexical.LexicalAnalyzer;
import inabit.compiler.lexical.Token;
import inabit.compiler.lexical.TokenClass;
import inabit.compiler.lexical.automaton.Automata;
import inabit.compiler.lexical.automaton.transitions.DigitTransition;
import inabit.compiler.lexical.automaton.transitions.ExclusiveTransition;
import inabit.compiler.lexical.automaton.transitions.InclusiveTransition;
import inabit.compiler.lexical.automaton.transitions.LetterTransition;
import inabit.compiler.lexical.automaton.transitions.WhiteSpaceTransition;

import java.util.ArrayList;
import java.util.List;


/**Rule compiler lexical analyzer*/
/**@author Rafael Rocha*/
public class InabitLexicalAnalyzer extends LexicalAnalyzer{

	public InabitLexicalAnalyzer() {
		super("Initial");
	}

	@Override
	protected void setup(Automata automaton) {
		for(InabitTokenClass tkClass : InabitTokenClass.values()) {
			if(tkClass.isUnivoque()) {
				addReservedWord(tkClass.getStateLabel(), tkClass);
			}
		}
		
		String id = InabitTokenClass.ID.toString();
		String int_cte = InabitTokenClass.INT_CTE.getStateLabel();
		String real_point = "realWithPoint";
		String real_cte = InabitTokenClass.REAL_CTE.getStateLabel();
		String comment = "on comment";
		String stringStart = "StringStart";
		String string_cte = InabitTokenClass.STRING_CTE.getStateLabel();
		
		String initial = automaton.getInitialState();
		automaton.addStates(id, int_cte, real_point, real_cte, comment, string_cte, stringStart);
		//avoid whitespaces to be recognized as tokens
		automaton.addTransition(new WhiteSpaceTransition(initial, initial));
		
		//id representation
		automaton.addTransition(new LetterTransition(initial, id));
		automaton.addTransition(new InclusiveTransition(initial, id, '_'));
		automaton.addTransition(new DigitTransition(id, id));
		automaton.addTransition(new LetterTransition(id, id));
		automaton.addTransition(new InclusiveTransition(id, id, '_'));
		
		//integer representations
		automaton.addTransition(new DigitTransition(initial, int_cte));
		automaton.addTransition(new DigitTransition(int_cte, int_cte));
		
		//real representation
		automaton.addTransition(new DigitTransition(real_point, real_cte));
		automaton.addTransition(new DigitTransition(real_cte, real_cte));
		automaton.addTransition(new InclusiveTransition(int_cte, real_point, '.'));
		
		//string representation
		automaton.addTransition(new InclusiveTransition(initial, stringStart, '"'));
		automaton.addTransition(new ExclusiveTransition(stringStart, stringStart, '"'));
		automaton.addTransition(new InclusiveTransition(stringStart, string_cte, '"'));
		
		//comments
		automaton.addTransition(new InclusiveTransition(initial, comment, '$'));
		automaton.addTransition(new ExclusiveTransition(comment, comment, '$'));
		automaton.addTransition(new InclusiveTransition(comment, initial, '$'));
		
		automaton.setFinalState(id, int_cte, real_point, real_cte);
	}

	@Override
	protected TokenClass getTokenClass(Automata automata, String state) {
		if(state.equals(InabitTokenClass.ID.toString())) {
			return InabitTokenClass.ID;
		}else if(state.equals(InabitTokenClass.REAL_CTE.getStateLabel())) {
			return InabitTokenClass.REAL_CTE;
		}else if(state.equals(InabitTokenClass.INT_CTE.getStateLabel())) {
			return InabitTokenClass.INT_CTE;
		}else if(state.equals(InabitTokenClass.STRING_CTE.getStateLabel())){
			return InabitTokenClass.STRING_CTE;
		}else if(automata.getInitialState().equals(state)) {
			return InabitTokenClass.EOF;
		}
		return null;
	}

	@Override
	protected List<? extends TokenClass> getTokenClasses() {
		List<InabitTokenClass> tkClasses = new ArrayList<InabitTokenClass>();
		for(InabitTokenClass tkClass : InabitTokenClass.values()) {
			tkClasses.add(tkClass);
		}
		return tkClasses;
	}

	@Override
	public TokenClass eof() {
		return InabitTokenClass.EOF;
	}

	@Override
	public void setTokenValue(Token tk, String recognizedWord) {
		if(tk.getTokenClass() == InabitTokenClass.STRING_CTE) {
			tk.setValue(recognizedWord.substring(1, recognizedWord.length()-1));//remove as aspas da string
		}else {
			tk.setValue(recognizedWord);
		}
	}

	

	
}
